package bcnet.service;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.Connection;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.TimeZone;
import java.util.logging.Level;

import org.json.JSONObject;

import bcnet.dao.UserCodeDao;
import bcnet.service.factory.PriceHistoryServiceFactory;

import com.google.appengine.api.memcache.ErrorHandlers;
import com.google.appengine.api.memcache.Expiration;
import com.google.appengine.api.memcache.MemcacheService;
import com.google.appengine.api.memcache.MemcacheServiceFactory;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;



public class StockManager{
	public Connection conn;
	public String etnetNewsURL = "http://www.etnet.com.hk/mobile/tc/quote_news_list.php?code=";
	public String money18NewsURL = "http://money18.on.cc/finnews/related_news.html?type=ncnews&symbol=";
	public String yahooFinanceURL = "http://finance.yahoo.com/q/hp?s=";
	//public String etnetURL = "https://www.hkdnr.hk/whois/whois.jsp?";
	public String googleFinanceURL = "http://www.google.com.hk/finance/historical?q=HKG:";
	
	PriceHistoryService priceHistoryService = PriceHistoryServiceFactory.getPriceHistoryService();

	public StockManager() {
	}

	public String getResults(String code, String detail, String refresh, String input) throws Exception{
        //UserService userService = UserServiceFactory.getUserService();
        //User user = userService.getCurrentUser();
		
		MemcacheService syncCache = MemcacheServiceFactory.getMemcacheService();
	    syncCache.setErrorHandler(ErrorHandlers.getConsistentLogAndContinue(Level.INFO));

        
        StringBuilder result = new StringBuilder();
        
        DecimalFormat df = new DecimalFormat("#.##");
        DecimalFormat df2 = new DecimalFormat("#,###");
        DecimalFormat df3 = new DecimalFormat("#.##");
        DecimalFormat dfSpread = new DecimalFormat("#.###");
               
		String[] codeArr;
		String[] detailArr;
		String[] refreshArr;
		
		codeArr = code.split(",");
		detailArr = detail.split(",");
		refreshArr = refresh.split(",");
				
		String styleDisplay = "";
		String arrowDisplay = "";
		String arrowStyle = "";
		String t = new String();
		String refreshRate = new String();

		String selectStop = "", select5 = "", select10 = "", select30 = "", select60 = "";
		
		String buyList="";
		String sellList="";
		String runningStatus="";
	
		for (int i=0; i<codeArr.length; i++){
			arrowStyle = "";
			if (detailArr[i].equals("0")){
				styleDisplay = "style=\"display:none; width:100% \"";
				arrowDisplay = "▼";
			}
			else if (detailArr[i].equals("1")){
				styleDisplay = "style=\"display:inline-block; width:100% \"";
				arrowDisplay = "▲";
			}
			
			selectStop = "";
			select5 = "";
			select10 = "";
			select30 = "";
			select60 = "";
			
			if(refreshArr[i].equals("stop")){
				selectStop = " selected=\"selected\" ";
			}
			else if(refreshArr[i].equals("5000")){
				select5 = " selected=\"selected\" ";
			}
			else if(refreshArr[i].equals("10000")){
				select10 = " selected=\"selected\" ";
			}
			else if(refreshArr[i].equals("30000")){
				select30 = " selected=\"selected\" ";
			}
			else if(refreshArr[i].equals("60000")){
				select60 = " selected=\"selected\" ";
			}
			
			refreshRate = "<select id=\"refreshRate"+codeArr[i]+"\" name=\"refreshRate"+codeArr[i]+"\" onchange=\"stopRefresh('"+codeArr[i]+"');\"> " +
			"<option value=\"stop\" "+selectStop+">-</option>" +
			"<option value=\"5000\" "+select5+">5</option>" +
			"<option value=\"10000\" "+select10+">10</option>" +
			"<option value=\"30000\" "+select30+">30</option>" +
			"<option value=\"60000\" "+select60+">60</option>" +
			"</select>";
			
	        StringBuilder sb = new StringBuilder();
	        
	        
	        String chartWidth = System.getProperty("chartWidth"); // show as 100% by default
	        
	        String m18_code = "";
	        
	        String m18_ltt = "";
	        double m18_np = 0.0;
	        long m18_vol = 0;
	        long m18_tvr = 0;
	        double m18_dyh = 0.0;
	        double m18_dyl = 0.0;
	        
	        String m18_name = "";
	        String m18_nameChi = "";
	        double m18_preCPrice = 0.0;
	        double m18_mthHigh = 0.0;
	        double m18_mthLow = 0.0;
	        double m18_wk52High = 0.0;
	        double m18_wk52Low = 0.0;
	        double m18_ma10 = 0.0;
	        double m18_ma20 = 0.0;
	        double m18_ma50 = 0.0;
	        //double m18_rsi10 = 0.0;
	        //double m18_rsi14 = 0.0;
	        //double m18_rsi20 = 0.0;
	        double rsi10 = 0.0;
	        double rsi20 = 0.0;
	        double m18_lotSize = 0.0;
	        
	        double m18_openPrice = 0.0;
	        
	        double m18_hsi_difference = 0.0;
	        double m18_hsi_volume = 0.0;
	        
	        String ch = "";
	        String ch_value = "";
	        String ch_pct = "";
	        
	        // For suggestion
	        //boolean isRise = false;
	        double spread = 0;
	        long projectedVol = 0;
	        String suggestion = "";
	        
	        String codeWithPaddingZero = codeArr[i].equalsIgnoreCase("H")||codeArr[i].equalsIgnoreCase("B")||codeArr[i].equalsIgnoreCase("S")?codeArr[i]:String.format("%05d",Integer.parseInt(codeArr[i]));
	        String codeWithPaddingZero4 = codeArr[i].equalsIgnoreCase("H")||codeArr[i].equalsIgnoreCase("B")||codeArr[i].equalsIgnoreCase("S")?codeArr[i]:String.format("%04d",Integer.parseInt(codeArr[i]));
	        //codeArr[i] = String.format("%05d",Integer.parseInt(codeArr[i]));
	        
	       
			String m18URL_1_daily = "http://money18.on.cc/js/daily/quote/";
			String m18URL_1_real = "http://money18.on.cc/js/real/quote/";
			String m18URL_1_open = "http://money18.on.cc/js/real/opening/";
			String m18URL_2 = "";
			String m18URL_3_daily = "_d.js?t=1402369860954";
			String m18URL_3_real = "_r.js?t=1402369860954";
			String m18URL_3_open = "_o.js?t=1402369860954";
			
			String m18URL_hsi = "http://money18.on.cc/js/real/index/HSI_r.js?t=1402369860954";
			
			String m18URL = "";
			
			String resultArr[];
			JSONObject obj1 = null;
				
			if(!codeArr[i].equalsIgnoreCase("H") && !codeArr[i].equalsIgnoreCase("B") && !codeArr[i].equalsIgnoreCase("S")){
					/* Real */
					m18URL_2 = codeWithPaddingZero;
					m18URL = m18URL_1_real + m18URL_2 + m18URL_3_real;
					
					URL url1 = new URL(m18URL);
					HttpURLConnection conn1;
					conn1 = (HttpURLConnection) url1.openConnection();
					
					System.out.println("M18 Real");
					conn1.setDoInput( true );
					conn1.setDoOutput( true );
					conn1.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
					conn1.setRequestProperty("Referer", "http://money18.on.cc/info/liveinfo_quote.html?symbol="+codeWithPaddingZero);
					DataOutputStream dos1 = new DataOutputStream( conn1.getOutputStream() );
					//String post = new String();
					//dos.writeBytes( post );
					dos1.flush();
					dos1.close();
					
					BufferedReader in1 = new BufferedReader( new InputStreamReader( conn1.getInputStream(), "utf-8") );
					
					
					while(  (t = in1.readLine()) != null){
						//System.out.println(t);
						sb.append(t);
					}
					resultArr = sb.toString().split("=");
					obj1 = new JSONObject(resultArr[1]);
		
					m18_code = codeWithPaddingZero;
					m18_ltt = obj1.getString("ltt");
					m18_np = obj1.getDouble("np");
					m18_vol = obj1.getLong("vol");
					m18_tvr = obj1.getLong("tvr");
					m18_dyh = obj1.getDouble("dyh");
					m18_dyl = obj1.getDouble("dyl");
					
					spread = m18_dyh - m18_dyl;
					projectedVol = priceHistoryService.getProjectedVol(m18_vol);
	
					// update decimal format
					if(m18_np <= 1.0){
						df = new DecimalFormat("###.###");
					}
					else if(m18_np <= 10.0){
						df = new DecimalFormat("###.##");
					}
					else if (m18_np <= 200.0){
						df = new DecimalFormat("###.#");
					}
					else if (m18_np <= 2000.0){
						df = new DecimalFormat("###");
					}
					
									
					sb.setLength(0);
					
					
					/* Daily */
					m18_name = (String)syncCache.get("m18_name_"+m18_code);
					m18_nameChi = (String)syncCache.get("m18_nameChi_"+m18_code);
					m18_preCPrice = (Double)syncCache.get("m18_preCPrice_"+m18_code)==null?0.0:(Double)syncCache.get("m18_preCPrice_"+m18_code);
					m18_mthHigh = (Double)syncCache.get("m18_mthHigh_"+m18_code)==null?0.0:(Double)syncCache.get("m18_mthHigh_"+m18_code);
					m18_mthLow = (Double)syncCache.get("m18_mthLow_"+m18_code)==null?0.0:(Double)syncCache.get("m18_mthLow_"+m18_code);;
					m18_wk52High = (Double)syncCache.get("m18_wk52High_"+m18_code)==null?0.0:(Double)syncCache.get("m18_wk52High_"+m18_code);
					m18_wk52Low = (Double)syncCache.get("m18_wk52Low_"+m18_code)==null?0.0:(Double)syncCache.get("m18_wk52Low_"+m18_code);
					m18_ma10 = (Double)syncCache.get("m18_ma10_"+m18_code)==null?0.0:(Double)syncCache.get("m18_ma10_"+m18_code);
					m18_ma20 = (Double)syncCache.get("m18_ma20_"+m18_code)==null?0.0:(Double)syncCache.get("m18_ma20_"+m18_code);
					m18_ma50 = (Double)syncCache.get("m18_ma50_"+m18_code)==null?0.0:(Double)syncCache.get("m18_ma50_"+m18_code);
					//m18_rsi10 = (Double)syncCache.get("m18_rsi10_"+m18_code)==null?0.0:(Double)syncCache.get("m18_rsi10_"+m18_code);
					//m18_rsi14 = (Double)syncCache.get("m18_rsi14_"+m18_code)==null?0.0:(Double)syncCache.get("m18_rsi14_"+m18_code);
					//m18_rsi20 = (Double)syncCache.get("m18_rsi20_"+m18_code)==null?0.0:(Double)syncCache.get("m18_rsi20_"+m18_code);
					rsi10 = (Double)syncCache.get("rsi10_"+codeArr[i])==null?0.0:(Double)syncCache.get("rsi10_"+codeArr[i]);
					rsi20 = (Double)syncCache.get("rsi20_"+codeArr[i])==null?0.0:(Double)syncCache.get("rsi20_"+codeArr[i]);
					
					m18_lotSize = (Double)syncCache.get("m18_lotSize_"+m18_code)==null?0.0:(Double)syncCache.get("m18_lotSize_"+m18_code);
					
				
				    //value = (byte[]) syncCache.get(key); // read from cache
					// if any one of the variable is not cached, http request
				    if (	m18_name == null ||
				    		m18_nameChi == null ||
				    		m18_preCPrice == 0.0 ||
				    		m18_mthHigh == 0.0 ||
				    		m18_mthLow == 0.0 ||
				    		m18_wk52High == 0.0 ||
				    		m18_wk52Low == 0.0 ||
				    		m18_ma10 == 0.0 ||
				    		m18_ma20 == 0.0 ||
				    		m18_ma50 == 0.0 ||
				    		//m18_rsi10 == 0.0 ||
				    		//m18_rsi14 == 0.0 ||
				    		//m18_rsi20 == 0.0 ||
		    				rsi10 == 0.0 ||
				    		rsi20 == 0.0 ||
				    		m18_lotSize == 0.0
				    ){
				    	System.out.println("M18 Daily");
						
						m18URL = m18URL_1_daily + m18URL_2 + m18URL_3_daily;
						
						URL url2 = new URL(m18URL);
						HttpURLConnection conn2;
						
						conn2 = (HttpURLConnection) url2.openConnection();
									
						conn2.setDoInput( true );
						conn2.setDoOutput( true );
						conn2.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
						conn2.setRequestProperty("Referer", "http://money18.on.cc/info/liveinfo_quote.html?symbol="+codeWithPaddingZero);
						DataOutputStream dos2 = new DataOutputStream( conn2.getOutputStream() );
						//String post = new String();
						//dos.writeBytes( post );
						dos2.flush();
						dos2.close();
						
						BufferedReader in2 = new BufferedReader( new InputStreamReader( conn2.getInputStream(), "big5") );
						
						while(  (t = in2.readLine()) != null){
							sb.append(t);
							//System.out.println(t);
						}
						resultArr = sb.toString().split("=");
						obj1 = new JSONObject(resultArr[1]);
			
						m18_name = obj1.getString("name");
						m18_nameChi = obj1.getString("nameChi");
						m18_preCPrice = obj1.getDouble("preCPrice");
						m18_mthHigh = obj1.getDouble("mthHigh");
						m18_mthLow = obj1.getDouble("mthLow");
						m18_wk52High = obj1.getDouble("wk52High");
						m18_wk52Low = obj1.getDouble("wk52Low");
						m18_ma10 = obj1.getDouble("ma10");
						m18_ma20 = obj1.getDouble("ma20");
						m18_ma50 = obj1.getDouble("ma50");
						//m18_rsi10 = obj1.getDouble("rsi10");
						//m18_rsi14 = obj1.getDouble("rsi14");
						//m18_rsi20 = obj1.getDouble("rsi20");
						rsi10 = priceHistoryService.getRSI(codeArr[i], 10);
						rsi20 = priceHistoryService.getRSI(codeArr[i], 20);
						m18_lotSize = obj1.getDouble("lotSize");
						
						syncCache.put("m18_name_"+m18_code, m18_name,Expiration.byDeltaSeconds(86400));
						syncCache.put("m18_nameChi_"+m18_code, m18_nameChi,Expiration.byDeltaSeconds(86400));
						syncCache.put("m18_preCPrice_"+m18_code, m18_preCPrice,Expiration.byDeltaSeconds(86400));
						syncCache.put("m18_mthHigh_"+m18_code, m18_mthHigh,Expiration.byDeltaSeconds(86400));
						syncCache.put("m18_mthLow_"+m18_code, m18_mthLow,Expiration.byDeltaSeconds(86400));
						syncCache.put("m18_wk52High_"+m18_code, m18_wk52High,Expiration.byDeltaSeconds(86400));
						syncCache.put("m18_wk52Low_"+m18_code, m18_wk52Low,Expiration.byDeltaSeconds(86400));
						syncCache.put("m18_ma10_"+m18_code, m18_ma10,Expiration.byDeltaSeconds(86400));
						syncCache.put("m18_ma20_"+m18_code, m18_ma20,Expiration.byDeltaSeconds(86400));
						syncCache.put("m18_ma50_"+m18_code, m18_ma50,Expiration.byDeltaSeconds(86400));
						//syncCache.put("m18_rsi10_"+m18_code, m18_rsi10,Expiration.byDeltaSeconds(86400));
						//syncCache.put("m18_rsi14_"+m18_code, m18_rsi14,Expiration.byDeltaSeconds(86400));
						//syncCache.put("m18_rsi20_"+m18_code, m18_rsi20,Expiration.byDeltaSeconds(86400));
						syncCache.put("rsi10_"+codeArr[i], rsi10,Expiration.byDeltaSeconds(86400));
						syncCache.put("rsi20_"+codeArr[i], rsi20,Expiration.byDeltaSeconds(86400));
						
						syncCache.put("m18_lotSize_"+m18_code, m18_lotSize,Expiration.byDeltaSeconds(86400));
						
				    }
					sb.setLength(0);
				    
				    
					/* Open */
					try{
						m18_openPrice = (Double)syncCache.get("m18_openPrice_"+m18_code)==null?0.0:(Double)syncCache.get("m18_openPrice_"+m18_code);
						if(m18_openPrice == 0.0){
							m18URL = m18URL_1_open + m18URL_2 + m18URL_3_open;
							
							URL url3 = new URL(m18URL);
							HttpURLConnection conn3;
							
							conn3 = (HttpURLConnection) url3.openConnection();
									
							System.out.println("M18 Open");
							conn3.setDoInput( true );
							conn3.setDoOutput( true );
							conn3.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
							conn3.setRequestProperty("Referer", "http://money18.on.cc/info/liveinfo_quote.html?symbol="+codeWithPaddingZero);
							DataOutputStream dos3 = new DataOutputStream( conn3.getOutputStream() );
							//String post = new String();
							//dos.writeBytes( post );
							dos3.flush();
							dos3.close();
							
							BufferedReader in3 = new BufferedReader( new InputStreamReader( conn3.getInputStream(), "big5") );
							
							while(  (t = in3.readLine()) != null){
								sb.append(t);
								//System.out.println(t);
							}
							resultArr = sb.toString().split("=");
							obj1 = new JSONObject(resultArr[1]);
				
							m18_openPrice = obj1.getDouble("openPrice");
							
							syncCache.put("m18_openPrice_"+m18_code, m18_openPrice,Expiration.byDeltaSeconds(86400));
							
						}
					}
					catch (Exception ex){
						m18_openPrice = 0.0;
					}
					
					sb.setLength(0);
					
					
					
					ch_value = dfSpread.format(m18_np - m18_preCPrice);
					ch_pct = df3.format((m18_np - m18_preCPrice)*100/m18_preCPrice);
					if(m18_np - m18_preCPrice > 0){
						ch = "+";
						//isRise = true;
					}
					if(m18_np - m18_preCPrice < 0){
						ch = "-";
						//isRise = false;
					}
					if(m18_np - m18_preCPrice == 0){
						ch = " ";
						//isRise = false;
					}
					
							
					
					
				}
				
				
				/* HSI */
				if(codeArr[i].equalsIgnoreCase("H")){

					try{
						m18URL = m18URL_hsi;
						
						URL url4 = new URL(m18URL);
						HttpURLConnection conn4;
						
						conn4 = (HttpURLConnection) url4.openConnection();
									
						conn4.setDoInput( true );
						conn4.setDoOutput( true );
						conn4.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
						conn4.setRequestProperty("Referer", "http://money18.on.cc/");
						DataOutputStream dos4 = new DataOutputStream( conn4.getOutputStream() );
						//String post = new String();
						//dos.writeBytes( post );
						dos4.flush();
						dos4.close();
						
						BufferedReader in4 = new BufferedReader( new InputStreamReader( conn4.getInputStream(), "big5") );
						
						while(  (t = in4.readLine()) != null){
							sb.append(t);
							//System.out.println(t);
						}
						resultArr = sb.toString().split("=");
						obj1 = new JSONObject(resultArr[1]);
			
						m18_ltt = obj1.getString("ltt");
						m18_preCPrice = obj1.getDouble("pc");
						m18_np = obj1.getDouble("value");
						m18_hsi_difference = obj1.getDouble("difference");
						m18_hsi_volume = obj1.getDouble("turnover");
						m18_dyh = obj1.getDouble("high");
						m18_dyl = obj1.getDouble("low");
						
						sb.setLength(0);	
						
						
						ch_value = dfSpread.format(m18_hsi_difference);
						ch_pct = df3.format((m18_hsi_difference)*100/m18_preCPrice);
						if(m18_hsi_difference > 0){
							ch = "+";
							//isRise = true;
						}
						if(m18_hsi_difference < 0){
							ch = "-";
							//isRise = false;
						}
						if(m18_hsi_difference == 0){
							ch = " ";
							//isRise = false;
						}
						
					}
					catch (Exception ex){
						//m18_openPrice = 0.0;
					}
				}
				
				runningStatus = priceHistoryService.getRunningStatus();
				// Buy List
				if(codeArr[i].equalsIgnoreCase("B")){
					buyList = priceHistoryService.getBuyList();
				}

				// Sell List
				if(codeArr[i].equalsIgnoreCase("S")){
					sellList = priceHistoryService.getSellList();
				}
				
				// although no showing additional text, still get the chart string (or the mem cache) in order to get the suggestion
				if(!codeArr[i].equalsIgnoreCase("H") && !codeArr[i].equalsIgnoreCase("B") && !codeArr[i].equalsIgnoreCase("S")){
					//System.out.println("XXX");
					priceHistoryService.getPriceChartString(codeArr[i],m18_np);
					priceHistoryService.getVolumeChartString(codeArr[i],m18_vol);
					priceHistoryService.getSpreadChartString(codeArr[i], m18_np, m18_dyh-m18_dyl);
				}
				
				suggestion = "-";
				if(!codeArr[i].equalsIgnoreCase("H") && !codeArr[i].equalsIgnoreCase("B") && !codeArr[i].equalsIgnoreCase("S")){
					suggestion = priceHistoryService.getSuggestion(codeArr[i], m18_np, spread, projectedVol, Double.parseDouble(ch_value),m18_preCPrice,m18_dyh,m18_dyl,rsi10,rsi20);
					if(suggestion.indexOf("B")>=0){
						arrowStyle = " buy ";
					}
					else if(suggestion.indexOf("S")>=0){
						arrowStyle = " sell ";
					}
					else if(suggestion.indexOf("N")>=0){
						arrowStyle = " cacheless ";
					}
					else if(suggestion.indexOf("-")>=0){
						arrowStyle = " ";
					}
				}
				
				// get the spread and volume stat for display
				double spreadAverage = priceHistoryService.getSpreadAverage(codeArr[i]);
				double spreadStdDev = priceHistoryService.getSpreadStdDev(codeArr[i]);
				double spreadStat = priceHistoryService.getStat(spread,spreadAverage,spreadStdDev);

				double volumeAverage = priceHistoryService.getVolumeAverage(codeArr[i]);
				double volumeStdDev = priceHistoryService.getVolumeStdDev(codeArr[i]);
				double volumeStat = priceHistoryService.getStat(projectedVol,volumeAverage,volumeStdDev);

				// get the up/down bar for display
				boolean upBar = m18_preCPrice <= m18_dyl?true:false;
				boolean downBar = m18_preCPrice >= m18_dyh?true:false;

				if (input.equals("0")){ //if mass refresh
					result.append("<div id=\"poolresult");
					result.append(codeArr[i]);
					result.append("\" name=\"poolresult");
					result.append(codeArr[i]);
					result.append("\" >");
				}
			

				result.append("<div class=\"code\"><span id=\"loading");
				result.append(codeArr[i]);
				result.append("\" name=\"loading");
				result.append(codeArr[i]);
				result.append("\" style=\"display: inline-block;\"><img width=\"16\" height=\"16\" src=\"images/ajax-loader-static.gif\" onclick=\"ajaxFunction('");
				result.append(codeArr[i]);
				result.append("');\"/></span>");

				result.append("<span id=\"animating");
				result.append(codeArr[i]);
				result.append("\" name=\"animating" );
				result.append(codeArr[i]);
				result.append("\" style=\"display: none;\"><img width=\"16\" height=\"16\" src=\"images/ajax-loader.gif\" /></span>");

				
				result.append("<span id=\"refresh");
				result.append(codeArr[i]);
				result.append("\" >");
				result.append(refreshRate);
				result.append("</span>");

				result.append("<B>&nbsp;");
				result.append(codeArr[i]);
				result.append(": </B>");

				
				result.append("<span onclick=\"toggle_visibility('detail");
				result.append(codeArr[i]);
				result.append("','arrow");
				result.append(codeArr[i]);
				if ( ch.startsWith("+")){
					result.append("');\" class=\"rise np\">");
				}
				else if (ch.startsWith("-")){
					result.append("');\" class=\"drop np\">");
				}
				else {
					result.append("');\" class=\"unchange np\">");
				}
				if(codeArr[i].equalsIgnoreCase("B") || codeArr[i].equalsIgnoreCase("S")){
					result.append(runningStatus);
				}
				else{
					result.append(m18_np);
					result.append("&nbsp;");
					result.append((ch.startsWith("+")?"+":"")+ch_value);
					if(!codeArr[i].equalsIgnoreCase("H")){
						result.append("&nbsp;");
						result.append("("+ch_pct+"%)");
					}
				}
				result.append("</span>");
				
				 
								
				result.append("<span>");
				result.append("<span id=\"arrow");
				result.append(codeArr[i]);
				result.append("\" class=\"right"+arrowStyle+"\" onclick=\"toggle_visibility('detail");
				result.append(codeArr[i]);
				result.append("','arrow");
				result.append(codeArr[i]);
				result.append("');\">");
				
				result.append(arrowDisplay);
				result.append("</span>");
				result.append("<span class=\"rightbutton\">");
				result.append("<button type=\"button\" onClick=\"deleteCode('"+codeArr[i]+"');\">-</button>");
				result.append("</span>");
				result.append("<br/></div>"); // end of onclick
				
				
				if(!codeArr[i].equalsIgnoreCase("H") && !codeArr[i].equalsIgnoreCase("B") && !codeArr[i].equalsIgnoreCase("S")){
					result.append("<span ");
					result.append(styleDisplay);
					result.append(" id=\"detail");
					result.append(codeArr[i]);
					result.append("\"><span class=\"additionTxt\">");
					result.append(m18_nameChi);
					result.append("<br/>Suggestion: ");
					result.append(suggestion);
					result.append("<br/>Volume Stat: ");
					result.append(volumeStat);
					result.append("<br/>Volume: ");
					result.append(df2.format(m18_vol));
					result.append(" (Pro: ");
					result.append(df2.format(projectedVol));
					result.append(")<br/>Volume Avg: ");
					result.append(df2.format(volumeAverage));
					result.append("<br/>Volume SD: ");
					result.append(df2.format(volumeStdDev));
					result.append("<br/>Spread Stat: ");
					result.append(spreadStat);
					result.append("<br/>Spread: ");
					result.append(dfSpread.format(spread));
					result.append("<br/>Spread Avg: ");
					result.append(dfSpread.format(spreadAverage));
					result.append("<br/>Spread SD: ");
					result.append(dfSpread.format(spreadStdDev));
					result.append("<br/>Up-bar: ");
					result.append(upBar);
					result.append("<br/>Down-bar: ");
					result.append(downBar);
					
					result.append("<br/>PC: ");
					result.append(m18_preCPrice);					
					//result.append("<br/>Open: ");
					//result.append(m18_openPrice);
					result.append("<br/>D: ");
					result.append(m18_dyl);
					result.append(" - ");
					result.append(m18_dyh);
					result.append("<br/>M: ");
					result.append(m18_mthLow);
					result.append(" - ");
					result.append(m18_mthHigh);
					result.append("<br/>Y: ");
					result.append(m18_wk52Low);
					result.append(" - ");
					result.append(m18_wk52High);
					result.append("<br/>MA10: ");
					result.append(m18_ma10);
					result.append("<br/>MA20: ");
					result.append(m18_ma20);
					result.append("<br/>MA50: ");
					result.append(m18_ma50);
					result.append("<br/>RSI10: ");
					result.append(df.format(rsi10));					
					//result.append("<br/>RSI14: ");
					//result.append(m18_rsi14);					
					result.append("<br/>RSI20: ");
					result.append(df.format(rsi20));					
					result.append("<br/>LOT: ");
					result.append(m18_lotSize + " ($" + df2.format(m18_lotSize * m18_np)+")");					
					//result.append("<br/>TO$: ");
					//result.append(df2.format(m18_tvr));
					
	//				result.append("<br/>Suggestion: ");

	//				result.append(suggestion);
					result.append("<br/>Last update: ");
					result.append(m18_ltt);
					result.append("<br/>News: <a target=\"_blank\" href=\""+etnetNewsURL+codeArr[i]+"\">ETNet</a>&nbsp;|&nbsp;<a target=\"_blank\" href=\""+money18NewsURL+codeWithPaddingZero+"\">Money18</a>&nbsp;|&nbsp;<a target=\"_blank\" href=\""+yahooFinanceURL+codeWithPaddingZero4+".HK\">Yahoo</a>&nbsp;|&nbsp;<a target=\"_blank\" href=\""+googleFinanceURL+codeWithPaddingZero4+"\">Google</a>");
	//				result.append(m18_ltt);
					
					/*
					//boolean hasHistory = priceHistoryService.hasHistory(codeArr[i]);
					if(detailArr[i].equals("1")){ // if refresh the price without showing the additional text, then dont call the google chart
						//result.append("<br/>");
						//result.append("<a href=\"deletePrice.jsp?code="+codeArr[i]+"\">Delete History</a>");
						result.append("<br/>");
						result.append("<iframe seamless style=\"width: 100%; height:400px; border: none; background-color: transparent;\" src=\"/priceChart.jsp?code="+codeArr[i]+"&np="+m18_np+"&chartWidth="+chartWidth+"\"></iframe>");
						//result.append("<br/>");
						//result.append("<iframe seamless style=\"width: 100%; height:450px; border: none; background-color: transparent;\" src=\"/volumeChart.jsp?code="+codeArr[i]+"&chartWidth=2600\"></iframe>");
						result.append("<br/>");
						result.append("<iframe seamless style=\"width: 100%; height:400px; border: none; background-color: transparent;\" src=\"/volumeChart2.jsp?code="+codeArr[i]+"&cv="+m18_vol+"&currentTimeString="+m18_ltt.split(" ")[1]+"&chartWidth="+chartWidth+"\"></iframe>");
						result.append("<br/>");
						result.append("<iframe seamless style=\"width: 100%; height:400px; border: none; background-color: transparent;\" src=\"/spreadChart.jsp?code="+codeArr[i]+"&np="+m18_np+"&spread="+dfSpread.format(m18_dyh-m18_dyl)+"&chartWidth="+chartWidth+"\"></iframe>");
						result.append("<br/>");
						result.append("<iframe id=\"trendID\" seamless style=\"width: 100%; height:400px; border: none; background-color: transparent;\" src=\"/trendChart.jsp?code="+codeArr[i]+"&np="+m18_np+"&chartWidth="+chartWidth+"\"></iframe>");						
					}
					*/
					
				}
			
				//HSI
				if(codeArr[i].equalsIgnoreCase("H")){
					result.append("<span ");
					result.append(styleDisplay);
					result.append(" id=\"detail");
					result.append(codeArr[i]);
					result.append("\"><span class=\"additionTxt\">");
					result.append("PC: ");
					result.append(m18_preCPrice);
					result.append("<br/>Volume: ");
					result.append(df2.format(m18_hsi_volume));
					
					/*
					result.append("<br/>D: ");
					result.append(m18_dyl);
					result.append(" - ");
					result.append(m18_dyh);
					*/
					result.append("<br/>Last update: ");
					result.append(m18_ltt);
				}
				
				//Buy List
				if(codeArr[i].equalsIgnoreCase("B")){
					result.append("<span ");
					result.append(styleDisplay);
					result.append(" id=\"detail");
					result.append(codeArr[i]);
					result.append("\"><span class=\"additionTxt\">");
					result.append(buyList);
					result.append("<a target=\"_blank\" href=\"/cron/addTask.jsp\">Refresh Buy/Sell List</a>");
				}
		
				//Sell List
				if(codeArr[i].equalsIgnoreCase("S")){
					result.append("<span ");
					result.append(styleDisplay);
					result.append(" id=\"detail");
					result.append(codeArr[i]);
					result.append("\"><span class=\"additionTxt\">");
					result.append(sellList);
					result.append("<a target=\"_blank\" href=\"/cron/addTask.jsp\">Refresh Buy/Sell List</a>");
				}
			
			result.append("</span>");	// end of detail
			
			if(input.equals("0")){
				result.append("</div>"); // end of poolresult0
				result.append("<hr id=\"hr"+codeArr[i]+"\">");
			}
					
		}
        
		return result.toString();
	}
	
	public String saveCode(String code, String refresh) throws Exception{
        UserService userService = UserServiceFactory.getUserService();
        User user = userService.getCurrentUser();
        UserCodeDao userCodeDao = new UserCodeDao();
        return userCodeDao.updateUserCode(user.getEmail(), code, refresh);
	}
	
	public String[] getCode(User user) throws Exception{
        UserCodeDao userCodeDao = new UserCodeDao();
        if (user != null){
        	return userCodeDao.getUserCode(user.getEmail());
        }
        else {
        	return new String[]{System.getProperty("default-code"),System.getProperty("default-refreshRate")};
        }
	}
	
	public String[] getRefreshSelected(String refresh) throws Exception{
		String refreshSelected[] = new String[5];
		refreshSelected[0]="";
		refreshSelected[1]="";
		refreshSelected[2]="";
		refreshSelected[3]="";
		refreshSelected[4]="";
		String selected = "selected=\"selected\"";
		if (refresh.equals("stop")){
			refreshSelected[0] = selected;
		}
		else if (refresh.equals("5000")){
			refreshSelected[1] = selected;
		}
		else if (refresh.equals("10000")){
			refreshSelected[2] = selected;
		}
		else if (refresh.equals("30000")){
			refreshSelected[3] = selected;
		}
		else if (refresh.equals("60000")){
			refreshSelected[4] = selected;
		}
		return refreshSelected;
	}
	
	public String getSysdate() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		sdf.setTimeZone(TimeZone.getTimeZone("GMT+8"));
		return sdf.format(Calendar.getInstance(TimeZone.getTimeZone("GMT+8")).getTime()).toString();
	}
	
	public String getSysYear() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
		sdf.setTimeZone(TimeZone.getTimeZone("GMT+8"));
		return sdf.format(Calendar.getInstance(TimeZone.getTimeZone("GMT+8")).getTime()).toString();
	}
	
	public boolean isFloat( String input ){  
	   try{  
	      Float.parseFloat( input );  
	      return true;  
	   }  
	   catch( Exception ex ){  
	      return false;  
	   }  
	} 

	public String genLoginLogoutUrl(String uri){
        UserService userService = UserServiceFactory.getUserService();
        User user = userService.getCurrentUser();
		String returnUrl = new String();
		if (user != null){
			returnUrl = "<div class=\"login\">"+user.getNickname()+" <a href=\""+userService.createLogoutURL(uri)+"\">Logout</a><BR/><span onclick=\"ajaxFunction2();\">Save</span></div>";
		}
		else{
			returnUrl = "<div class=\"login\"><a href=\""+userService.createLoginURL(uri)+"\">Login</a></div>";
		}
		return returnUrl;
			
	}
	
}